﻿#pragma once

#include <exception>
#include <memory>
#include <mutex>
#include <thread>
#include <type_traits>
namespace hhfox {

template < typename T > class Singleton {
public:
    template < typename... Args > static std::unique_ptr< T >& createInstance( Args&&... args ) {
        std::call_once( _one, [ & ]() {
            if ( !_instance )
                _instance.reset( new T( std::forward< Args >( args )... ) );
        } );
        return _instance;
    }

    static std::unique_ptr< T >& getInstance() {
        if ( !_instance )
            throw( std::runtime_error( "instance is nullptr" ) );
        return _instance;
    }

private:
    Singleton( const Singleton& ) = delete;
    Singleton( Singleton&& )      = delete;
    Singleton& operator=( const Singleton& ) = delete;

private:
    static std::unique_ptr< T > _instance;
    static std::once_flag       _one;
};

template < typename T > std::unique_ptr< T > Singleton< T >::_instance = std::unique_ptr< T >( nullptr );

template < typename T > std::once_flag Singleton< T >::_one;
}  // namespace hhfox